package jdos.cpu.core_normal;

import jdos.cpu.*;
import jdos.cpu.core_dynamic.Mod;
import jdos.cpu.core_normal.Code.BTx;
import jdos.cpu.core_normal.Code.JMP;
import jdos.cpu.core_normal.Code.LxS;
import jdos.cpu.core_normal.Code.PopS;
import jdos.cpu.core_normal.Code.PushS;
import jdos.cpu.core_normal.Code.SETcc;
import jdos.cpu.core_normal.Code.Targets;
import jdos.hardware.Memory;
import jdos.misc.Log;

//0
public class CodeExt extends StringOp {

	static public OP[] ops = new OP[0x100];

	static {

		for (int i = 0; i < ops.length; i++)
			ops[i] = Code.not_handled;

		/* Group 7 Ew */
		ops[0x01] = new OP() {
			final public int call() {
				Targets t = Code.getTargets(true);
				switch (t.which) {

				case 0x04: /* SMSW */
					break;
				default:
					break;
				}

				return HANDLED;
			}
		};

		/* LAR Gw,Ew */
		ops[0x02] = new OP() {
			final public int call() {
				System.out.print("fdsfewfea6");System.exit(0);
				Targets t = Code.getTargets(true);
				//t.g.write(CPU.CPU_LAR(t.e.read() & 0xFFFF, t.g.read()));
				return HANDLED;
			}
		};

		/* LSL Gw,Ew */
		ops[0x03] = new OP() {
			final public int call() {
				System.out.print("fdsfewfea7");System.exit(0);
				Targets t = Code.getTargets(true);
				//t.g.write(CPU.CPU_LSL(t.e.read() & 0xFFFF, t.g.read()));
				return HANDLED;
			}
		};

		/* WBINVD */
		ops[0x09] = ops[0x08];

		/*
		0F0D NOP
		Intel 64 and IA-32 Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z, Two-byte Opcode Map
		AMD architecture maps 3DNow! PREFETCH instructions here
		*/
		ops[0x0D] = new OP() {
			final public int call() {
				return HANDLED;
			}
		};

		/* WRMSR */
		ops[0x30] = new OP() {
			final public int call() {
				System.out.print("fdsfewfea8");System.exit(0);
//				if (CPU.cpu.cpl != 0) return EXCEPTION(CPU.EXCEPTION_GP);
//				CPU.writeMSR(CPU_Regs.reg_ecx.dword, ((CPU_Regs.reg_edx.dword & 0xFFFFFFFFl) << 32) | (CPU_Regs.reg_eax.dword & 0xFFFFFFFFl));
				return HANDLED;
			}
		};

		/* RDMSR */
		ops[0x32] = new OP() {
			final public int call() {
				System.out.print("fdsfewfea9");System.exit(0);
//				if (CPU.cpu.cpl != 0) return EXCEPTION(CPU.EXCEPTION_GP);
//				long result = CPU.readMSR(CPU_Regs.reg_ecx.dword);
//				CPU_Regs.reg_eax.dword = (int) result;
//				CPU_Regs.reg_edx.dword = (int) (result >>> 32);
				return HANDLED;
			}
		};

		/* JO   */ ops[0x80] = new JMP(0x0, true);
		/* JNO  */ ops[0x81] = new JMP(0x1, true);
		/* JB   */ ops[0x82] = new JMP(0x2, true);
		/* JNB  */ ops[0x83] = new JMP(0x3, true);
		/* JZ   */ ops[0x84] = new JMP(0x4, true);
		/* JNZ  */ ops[0x85] = new JMP(0x5, true);
		/* JBE  */ ops[0x86] = new JMP(0x6, true);
		/* JNBE */ ops[0x87] = new JMP(0x7, true);
		/* JS   */ ops[0x88] = new JMP(0x8, true);
		/* JNS  */ ops[0x89] = new JMP(0x9, true);
		/* JP   */ ops[0x8a] = new JMP(0xa, true);
		/* JNP  */ ops[0x8b] = new JMP(0xb, true);
		/* JL   */ ops[0x8c] = new JMP(0xc, true);
		/* JNL  */ ops[0x8d] = new JMP(0xd, true);
		/* JLE  */ ops[0x8e] = new JMP(0xe, true);
		/* JNLE */ ops[0x8f] = new JMP(0xf, true);

		/* SETO   */ ops[0x90] = new SETcc(0x0);
		/* SETNO  */ ops[0x91] = new SETcc(0x1);
		/* SETB   */ ops[0x92] = new SETcc(0x2);
		/* SETNB  */ ops[0x93] = new SETcc(0x3);
		/* SETZ   */ ops[0x94] = new SETcc(0x4);
		/* SETNZ  */ ops[0x95] = new SETcc(0x5);
		/* SETBE  */ ops[0x96] = new SETcc(0x6);
		/* SETNBE */ ops[0x97] = new SETcc(0x7);
		/* SETS   */ ops[0x98] = new SETcc(0x8);
		/* SETNS  */ ops[0x99] = new SETcc(0x9);
		/* SETP   */ ops[0x9a] = new SETcc(0xa);
		/* SETNP  */ ops[0x9b] = new SETcc(0xb);
		/* SETL   */ ops[0x9c] = new SETcc(0xc);
		/* SETNL  */ ops[0x9d] = new SETcc(0xd);
		/* SETLE  */ ops[0x9e] = new SETcc(0xe);
		/* SETNLE */ ops[0x9f] = new SETcc(0xf);

		/* PUSH FS */ ops[0xa0] = new PushS(4);
		/* POP  FS */ ops[0xa1] = new PopS(4);

		/* BT Ew,Gw */
		ops[0xa3] = new BTx(0);

		/* SHLD Ew,Gw,Ib */
		ops[0xa4] = new OP() {
			final public int call() {
				Targets t = Code.getTargets(true);
				if ((prefixes & Core.PREFIX_DW) != 0) {
					int op3 = Fetchb() & 0x1F;
					if (op3 != 0) {
						t.e.write(DSHLD(t.g.read(), op3, t.e.read()));
					}
				} else {
					int op3 = Fetchb();//amount
					if ((op3 & 0x1f) != 0) {
						t.e.write(DSHLW(t.g.read(), op3, t.e.read()));
					}
				}
				return HANDLED;
			}
		};

		/* SHLD Ew,Gw,CL */
		ops[0xa5] = new OP() {
			final public int call() {
				Targets t = Code.getTargets(true);
				if ((prefixes & Core.PREFIX_DW) != 0) {
					int op3 = reg_ecx.dword & 0x1f;
					if (op3 != 0) {
						t.e.write(DSHLD(t.g.read(), op3, t.e.read()));
					}
				} else {
					int op3 = reg_ecx.low();//amount
					if ((op3 & 0x1f) != 0) {
						t.e.write(DSHLW(t.g.read(), op3, t.e.read()));
					}
				}
				return HANDLED;
			}
		};

		/* PUSH GS */ ops[0xa8] = new PushS(5);
		/* POP  GS */ ops[0xa9] = new PopS(5);

		/* BTS Ew,Gw */
		ops[0xab] = new BTx(1);

		/* SHRD Ew,Gw,Ib */
		ops[0xac] = new OP() {
			final public int call() {
				Targets t = Code.getTargets(true);
				if ((prefixes & Core.PREFIX_DW) != 0) {
					int op3 = Fetchb() & 0x1F;
					if (op3 != 0) {
						t.e.write(DSHRD(t.g.read(), op3, t.e.read()));
					}
				} else {
					int op3 = Fetchb();//amount
					if ((op3 & 0x1f) != 0) {
						t.e.write(DSHRW(t.g.read(), op3, t.e.read()));
					}
				}
				return HANDLED;
			}
		};

		/* SHRD Ew,Gw,CL */
		ops[0xad] = new OP() {
			final public int call() {
				Targets t = Code.getTargets(true);
				if ((prefixes & Core.PREFIX_DW) != 0) {
					int op3 = reg_ecx.dword & 0x1f;
					if (op3 != 0) {
						t.e.write(DSHRD(t.g.read(), op3, t.e.read()));
					}
				} else {
					int op3 = reg_ecx.low();//amount
					if ((op3 & 0x1f) != 0) {
						t.e.write(DSHRW(t.g.read(), op3, t.e.read()));
					}
				}
				return HANDLED;
			}
		};

		/* IMUL Gw,Ew */
		ops[0xaf] = new OP() {
			final public int call() {
				Targets t = Code.getTargets(true);
				if ((prefixes & Core.PREFIX_DW) != 0) {
					t.g.write(DIMULD(t.e.read(), t.g.read()));
				} else {
					t.g.write(DIMULW(t.e.read(), t.g.read()));
				}
				return HANDLED;
			}
		};

		/* LSS Ew */ ops[0xb2] = new LxS(2);

		/* BTR Ew,Gw */
		ops[0xb3] = new BTx(2);

		/* LFS Ew */ ops[0xb4] = new LxS(4);
		/* LGS Ew */ ops[0xb5] = new LxS(5);
		
//		/* MOVZX Gw,Eb */
//		ops[0xb6] = new OP() {
//			Targets t;
//			final public int call() {
//				t = Code.getTargets(true);
//				int val = t.e.read() & 0xFF;
//				t.g.write(val);
//				return HANDLED;
//			}
//		};

		/* MOVZX Gw,Eb */
		ops[0xb6] = new OP() {
			final public int call() {
				/*Bit8u*/int rm = Fetchb();
				if ((prefixes & Core.PREFIX_DW) != 0) {
					if (rm >= 0xc0) {
						Mod.gw(rm).dword = Mod.eb(rm).get8();
					} else {
						/*PhysPt*/int eaa = getEaa(rm);
						Mod.gw(rm).dword = Memory.mem_readb(eaa);
					}
				} else {
					if (rm >= 0xc0) {
						Mod.gw(rm).word(Mod.eb(rm).get8());
					} else {
						/*PhysPt*/int eaa = getEaa(rm);
						Mod.gw(rm).word(Memory.mem_readb(eaa));
					}
				}
				return HANDLED;
			}
		};

		/* MOVZX Gw,Ew */
		ops[0xb7] = new OP() {
				Targets t;
			final public int call() {
				t = Code.getTargets(true);
				int val = t.e.read() & 0xFFFF;
				t.g.write(val);
				return HANDLED;
			}
		};

		//
		//		/* GRP8 Ew,Ib */
		//		ops[0x1ba] = new OP() {
		//			final public int call() {
		//				Flags.FillFlags();
		//				Targets t = getTargets(true);
		//				int b = Fetchb();
		//				if ((prefixes & Core.PREFIX_DW) != 0) {
		//					int old = t.e.read();
		//					int mask = 1 << (b & 31);
		//					SETFLAGBIT(CF, (old & mask) != 0);
		//					switch (t.which) {
		//					case 4: /* BT */
		//						break;
		//					case 5: /* BTS */
		//						t.e.write(old | mask);
		//						break;
		//					case 6: /* BTR */
		//						t.e.write(old & ~mask);
		//						break;
		//					case 7: /* BTC */
		//						t.e.write(old ^ mask);
		//					default:
		//						Log.exit("CPU:66:0F:BA:Illegal subfunction " + Integer.toString(t.which, 16));
		//					}
		//				} else {
		//					int old = t.e.read();
		//					int mask = 1 << (b & 15);
		//					SETFLAGBIT(CF, (old & mask) != 0);
		//					switch (t.which) {
		//					case 4: /* BT */
		//						break;
		//					case 5: /* BTS */
		//						t.e.write(old | mask);
		//						break;
		//					case 6: /* BTR */
		//						t.e.write(old & ~mask);
		//						break;
		//					case 7: /* BTC */
		//						t.e.write(old ^ mask);
		//						break;
		//					default:
		//						Log.exit("CPU:0F:BA:Illegal subfunction " + Integer.toString(t.which, 16));
		//					}
		//				}
		//				return HANDLED;
		//			}
		//		};

		/* GRP8 Ew,Ib */
		ops[0xba] = new OP() {
			final public int call() {
				if ((prefixes & Core.PREFIX_DW) != 0) {
					FillFlags();
					int rm = Fetchb();
					if (rm >= 0xc0) {
						/*Bit32u*/int mask = 1 << (Fetchb() & 31);
						Reg eard = Mod.ew(rm);//Mod.ew(rm)
						SETFLAGBIT(CF, (eard.dword & mask) != 0);
						switch (rm & 0x38) {
						case 0x20: /* BT */
							break;
						case 0x28: /* BTS */
							eard.dword |= mask;
							break;
						case 0x30: /* BTR */
							eard.dword &= ~mask;
							break;
						case 0x38: /* BTC */
							if (GETFLAG(CF) != 0) eard.dword &= ~mask;
							else eard.dword |= mask;
							break;
						default:
							Log.exit("CPU:66:0F:BA:Illegal subfunction " + Integer.toString(rm & 0x38, 16));
						}
					} else {
						/*PhysPt*/int eaa = getEaa(rm);
						/*Bit32u*/int old = Memory.mem_readd(eaa);
						/*Bit32u*/int mask = 1 << (Fetchb() & 31);
						switch (rm & 0x38) {
						case 0x20: /* BT */
							break;
						case 0x28: /* BTS */
							Memory.mem_writed(eaa, old | mask);
							break;
						case 0x30: /* BTR */
							Memory.mem_writed(eaa, old & ~mask);
							break;
						case 0x38: /* BTC */
							if (GETFLAG(CF) != 0) old &= ~mask;
							else old |= mask;
							Memory.mem_writed(eaa, old);
							break;
						default:
							Log.exit("CPU:66:0F:BA:Illegal subfunction " + Integer.toString(rm & 0x38, 16));
						}
						SETFLAGBIT(CF, (old & mask) != 0);
					}

				} else {

					Flags.FillFlags();
					/*Bit8u*/int rm = Fetchb();
					if (rm >= 0xc0) {
						/*Bit16u*/int mask = 1 << (Fetchb() & 15);
						SETFLAGBIT(CF, (Mod.ew(rm).word() & mask) != 0);
						switch (rm & 0x38) {
						case 0x20: /* BT */
							break;
						case 0x28: /* BTS */
							Mod.ew(rm).word(Mod.ew(rm).word() | mask);
							break;
						case 0x30: /* BTR */
							Mod.ew(rm).word(Mod.ew(rm).word() & ~mask);
							break;
						case 0x38: /* BTC */
							Mod.ew(rm).word(Mod.ew(rm).word() ^ mask);
							break;
						default:
							Log.exit("CPU:0F:BA:Illegal subfunction " + Integer.toString(rm & 0x38, 16));
						}
					} else {
						/*PhysPt*/int eaa = getEaa(rm);
						/*Bit16u*/int old = Memory.mem_readw(eaa);
						/*Bit16u*/int mask = 1 << (Fetchb() & 15);
						SETFLAGBIT(CF, (old & mask) != 0);
						switch (rm & 0x38) {
						case 0x20: /* BT */
							break;
						case 0x28: /* BTS */
							Memory.mem_writew(eaa, old | mask);
							break;
						case 0x30: /* BTR */
							Memory.mem_writew(eaa, old & ~mask);
							break;
						case 0x38: /* BTC */
							Memory.mem_writew(eaa, old ^ mask);
							break;
						default:
							Log.exit("CPU:0F:BA:Illegal subfunction " + Integer.toString(rm & 0x38, 16));
						}
					}
				}
				return HANDLED;
			}
		};

		/* BTC Ew,Gw */
		ops[0xbb] = new BTx(3);

		/* BSF Gw,Ew */
		ops[0xbc] = new OP() {
			final public int call() {
				Targets t = Code.getTargets(true);
				/*Bit16u*/int result;
				int value = t.e.read();
				if (value == 0) {
					SETFLAGBIT(ZF, true);
				} else {
					result = 0;
					while ((value & 0x01) == 0) {
						result++;
						value >>= 1;
					}
					SETFLAGBIT(ZF, false);
					t.g.write(result);
				}
				return HANDLED;
			}
		};

		/* BSR Gw,Ew */
		ops[0xbd] = new OP() {
			final public int call() {
				Targets t = Code.getTargets(true);
				/*Bit16u*/int result;
				int value = t.e.read();
				if (value == 0) {
					SETFLAGBIT(ZF, true);
				} else {
					if ((prefixes & Core.PREFIX_DW) != 0) {
						result = 31; // Operandsize-1
						while ((value & 0x80000000) == 0) {
							result--;
							value <<= 1;
						}
					} else {
						result = 15; // Operandsize-1
						while ((value & 0x8000) == 0) {
							result--;
							value <<= 1;
						}
					}
					SETFLAGBIT(ZF, false);
					t.g.write(result);
				}
				return HANDLED;
			}
		};

		/* MOVSX Gw,Eb */
		ops[0xbe] = new OP() {
			final public int call() {
				/*Bit8u*/int rm = Fetchb();
				if ((prefixes & Core.PREFIX_DW) != 0) {
					if (rm >= 0xc0) {
						Mod.gw(rm).dword = (byte) (Mod.eb(rm).get8());
					} else {
						/*PhysPt*/int eaa = getEaa(rm);
						Mod.gw(rm).dword = (byte) Memory.mem_readb(eaa);
					}
				} else {
					if (rm >= 0xc0) {
						Mod.gw(rm).word(Mod.eb(rm).get8());
					} else {
						/*PhysPt*/int eaa = getEaa(rm);
						Mod.gw(rm).word((byte) Memory.mem_readb(eaa));
					}
				}
				return HANDLED;
			}
		};

		/* MOVSX Gw,Ew */
		ops[0xbf] = new OP() {
			final public int call() {
				/*Bit8u*/int rm = Fetchb();
				if ((prefixes & Core.PREFIX_DW) != 0) {
					if (rm >= 0xc0) {
						Mod.gw(rm).dword = (short) (Mod.ew(rm).word());
					} else {
						/*PhysPt*/int eaa = getEaa(rm);
						Mod.gw(rm).dword = (short) Memory.mem_readw(eaa);
					} // Yes that short signed cast is intentional
				} else {
					if (rm >= 0xc0) {
						Mod.gw(rm).word(Mod.ew(rm).word());
					} else {
						/*PhysPt*/int eaa = getEaa(rm);
						Mod.gw(rm).word(Memory.mem_readw(eaa));
					}
				}
				return HANDLED;
			}
		};

	}

}
